/*
	A class to hold, drag, and draw a geographic point.
	Requirements:
	- earth.js
	- helperFunctions.js
*/

// the meters/pixel change in altitude when moving a point.
const METERS_PER_PIXEL_ALTITUDE_CHANGE = 0.3;

const IMAGEHREF = (Site.DEBUG)? 'http://localhost:8080/live3dstatic/images/' : 'http://www.projectlive3d.com/live3dstatic/images/'

const EARTH_PIN_INSTEAD_OF_SQUARE = true;
const EARTH_PIN_PREFEX = EARTH_PIN_INSTEAD_OF_SQUARE ? "pin-" : "";

const ICON_SCALE = EARTH_PIN_INSTEAD_OF_SQUARE ? 0.5 : 0.25;

// a class to hold a point in 3D.
function Point3D( lat, lon, alt, color ) {
	this.lat = lat;
	this.lon = lon;
	this.alt = alt;
	this.color = color;
	this.snapped = false;

	this.movedPoint = false;
	this.hitBuilding = false;
	
	this.placemark = ge.createPlacemark('');
	
	this.makeIcon();
	
	this.point = ge.createPoint('');
	this.point.setAltitudeMode(ge.ALTITUDE_ABSOLUTE);
	this.point.setLatitude(lat);
	this.point.setLongitude(lon);
	this.point.setAltitude(alt);
	this.placemark.setGeometry(this.point);
	
	this.parentTriangles = new Array();
	this.lastY = -1;
}

// make the icon for a placemark.
Point3D.prototype.makeIcon = function() {
	this.icon = ge.createIcon('');

	if ( this.snapped ) { 
		this.icon.setHref(IMAGEHREF + "pins/" + EARTH_PIN_PREFEX + this.color + 'snap.png'); 
	} else { 
		this.icon.setHref(IMAGEHREF + "pins/" + EARTH_PIN_PREFEX + this.color + 'unsnap.png'); 
	}
	
	var style = ge.createStyle('');
	style.getIconStyle().setIcon(this.icon);
	style.getIconStyle().setScale(ICON_SCALE);
	this.placemark.setStyleSelector(style);
}

Point3D.prototype.changeToPrevious = function() { }

// sets the location of a point.
Point3D.prototype.setLoc = function( lat, lon, alt ) {
	this.lat = lat;
	this.lon = lon;
	this.alt = alt;
	this.point.setLatitude(lat);
	this.point.setLongitude(lon);
	this.point.setAltitude(alt);
}

// draws the point.
Point3D.prototype.draw = function() {
	// change the snapping icon, if you need to.
	this.makeIcon();
	ge.getFeatures().appendChild(this.placemark);
}

// undraws the point.
Point3D.prototype.undraw = function() {
	if (this.placemark){
		 ge.getFeatures().removeChild(this.placemark);
	}
}

// moves the point, or changes its altitude.
Point3D.prototype.movePoint = function( kmlEvent ) {
	kmlEvent.preventDefault();
	
	var lat = this.lat;
	var lon = this.lon;
	var alt = this.alt;
	
	if ( kmlEvent.getShiftKey() ) {
		// if the user is holding shift, just change altitude.
		var newY = kmlEvent.getScreenY();
		var diff = 0;
		if (this.lastY == -1){
			this.lastY = newY + 10;
		}
		else{
			diff = this.lastY - newY;
		}
		alt = alt + METERS_PER_PIXEL_ALTITUDE_CHANGE * diff;
		this.lastY = newY;

	} else {
		// if the user is not holding shift, just do a simple hit test.
		var ht = absoluteHitTestPixels(kmlEvent.getClientX(), kmlEvent.getClientY());
		if ( ht == null )
			return;
			
		// you can leave this point as is, but to avoid z-fighting, I'm going to
		// bring it slightly closer to the camera.
		var camera = ge.getView().copyAsCamera(ge.ALTITUDE_ABSOLUTE);
		var offset = 0.75; // meters

        var metersPerLat = distance(camera.getLatitude(),camera.getLongitude(),camera.getAltitude(),
                                    camera.getLatitude() + 0.00001,camera.getLongitude(),camera.getAltitude()) / 0.00001;
        var metersPerLon = distance(camera.getLatitude(),camera.getLongitude(),camera.getAltitude(),
                                    camera.getLatitude(),camera.getLongitude() + 0.00001,camera.getAltitude()) / 0.00001;
        
        var vec = {x:0, y:0, z:0};
        vec.x = (ht.lon - camera.getLongitude()) * metersPerLon;
        vec.y = (ht.lat - camera.getLatitude()) * metersPerLat;
        vec.z = (ht.alt - camera.getAltitude());
        mag = Math.sqrt(vec.x*vec.x + vec.y*vec.y + vec.z*vec.z)
        
        var offsetLocation = {x:0, y:0, z:0};
        offsetLocation.x = vec.x - vec.x / mag * offset;
        offsetLocation.y = vec.y - vec.y / mag * offset;
        offsetLocation.z = vec.z - vec.z / mag * offset;
        
		lat = camera.getLatitude() + offsetLocation.y / metersPerLat;
		lon = camera.getLongitude() + offsetLocation.x / metersPerLon;
		alt = camera.getAltitude() + offsetLocation.z;
		this.lastY = kmlEvent.getScreenY();
	}
	// make sure we don't go underground.
	alt = Math.max(alt, ge.getGlobe().getGroundAltitude(lat, lon));
	
	this.setLoc(lat, lon, alt);
	this.movedPoint = true;
	
	for ( var i = 0; i < this.parentTriangles.length; i++ ) {
		this.parentTriangles[i].updateEdges();
		this.parentTriangles[i].draw();
	}
	
	this.movedPoint = true;
}

Point3D.prototype.addParentTriangle = function( triangle ) {
	this.parentTriangles[this.parentTriangles.length] = triangle;
}

Point3D.prototype.removeParents = function() {
	this.parentTriangles = new Array();
}